<template>
  <el-dialog
    v-model="dialogVisible"
    title="AI 助手"
    width="60%"
    :close-on-click-modal="false"
    :before-close="handleClose"
  >
    <div class="chat-container">
      <!-- 连接状态显示 -->
      <div class="connection-status" :class="{ connected: isConnected }">
        <el-icon class="status-icon"><Connection /></el-icon>
        {{ isConnected ? 'AI 服务已连接' : '正在连接 AI 服务...' }}
      </div>

      <!-- 聊天记录区域 -->
      <div class="chat-messages" ref="messagesContainer">
        <div v-for="(message, index) in messages" :key="index" 
             :class="['message', message.role === 'user' ? 'user-message' : 'ai-message']">
          <div class="message-content">
            <div v-if="message.role === 'user'" class="user-content">
              {{ message.content }}
            </div>
            <div v-else-if="message.role === 'reasoning'" class="reasoning-content">
              {{ message.content }}
            </div>
            <div v-else class="ai-content markdown-body" v-html="renderMarkdown(message.content)"></div>
          </div>
        </div>
        <div v-if="isThinking" class="message ai-message">
          <div class="message-content thinking-content">
            <el-icon class="thinking-icon"><Loading /></el-icon>
            正在思考...
          </div>
        </div>
      </div>

      <!-- 输入区域 -->
      <div class="chat-input">
        <el-input
          v-model="userInput"
          type="textarea"
          :rows="3"
          placeholder="请输入您的问题..."
          :disabled="!isConnected || isThinking"
          @keyup.enter.ctrl="handleSend"
        />
        <div class="input-actions">
          <span class="hint">Ctrl + Enter 发送</span>
          <el-button 
            type="primary" 
            @click="handleSend"
            :loading="isThinking"
            :disabled="!isConnected || !userInput.trim()"
          >
            发送
          </el-button>
        </div>
      </div>
    </div>
  </el-dialog>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Loading, Connection } from '@element-plus/icons-vue'
import MarkdownIt from 'markdown-it'
import config from "@/config"

const props = defineProps({
  modelValue: Boolean,
})

const emit = defineEmits(['update:modelValue'])

// 状态
const userInput = ref('')
const messages = ref([])
const isThinking = ref(false)
const isConnected = ref(false)
const messagesContainer = ref(null)
let ws = null
let reconnectAttempts = 0
const MAX_RECONNECT_ATTEMPTS = 3

// Markdown 渲染器
const md = new MarkdownIt({
  html: true,
  breaks: true,
  linkify: true
})

// 计算属性
const dialogVisible = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value)
})

// 渲染 Markdown
const renderMarkdown = (content) => {
  return md.render(content)
}

// 滚动到底部
const scrollToBottom = async () => {
  await nextTick()
  if (messagesContainer.value) {
    messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
  }
}

// 初始化 WebSocket 连接
const initWebSocket = () => {
  if (ws?.readyState === WebSocket.OPEN) return

  try {
    ws = new WebSocket(config.AI_URL)

    ws.onopen = () => {
      console.log('WebSocket连接已建立')
      isConnected.value = true
      reconnectAttempts = 0
    }

    ws.onclose = () => {
      console.log('WebSocket连接已关闭')
      isConnected.value = false
      if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
        reconnectAttempts++
        setTimeout(initWebSocket, 1000 * reconnectAttempts)
      } else {
        ElMessage.error('AI 服务连接失败，请稍后重试')
      }
    }

    ws.onerror = (error) => {
      console.error('WebSocket错误:', error)
      isConnected.value = false
    }

    ws.onmessage = handleMessage
  } catch (error) {
    console.error('创建WebSocket连接错误:', error)
    isConnected.value = false
  }
}

// 处理收到的消息
const handleMessage = (event) => {
  try {
    const data = JSON.parse(event.data)
    if (data.type === 'reply') {
      if (data.messageType === 'reasoning') {
        // 处理推理过程
        if (messages.value.length > 0 && messages.value[messages.value.length - 1].role === 'reasoning') {
          // 更新现有的推理消息
          messages.value[messages.value.length - 1].content += data.content
        } else {
          // 添加新的推理消息
          messages.value.push({
            role: 'reasoning',
            content: data.content
          })
        }
        scrollToBottom()
      } else if (data.messageType === 'content') {
        if (data.content) {
          // 更新最后一条AI消息，或添加新消息
          if (messages.value.length > 0 && messages.value[messages.value.length - 1].role === 'assistant') {
            messages.value[messages.value.length - 1].content += data.content
          } else {
            messages.value.push({
              role: 'assistant',
              content: data.content
            })
          }
          scrollToBottom()
        } else {
          isThinking.value = false
        }
      }
    }
  } catch (error) {
    console.error('处理消息错误:', error)
    handleError()
  }
}

// 发送消息
const handleSend = () => {
  const message = userInput.value.trim()
  if (!message || isThinking.value || !isConnected.value) return

  // 添加用户消息
  messages.value.push({
    role: 'user',
    content: message
  })
  userInput.value = ''
  scrollToBottom()

  isThinking.value = true

  // 发送消息
  const msg = {
    type: 'prompt',
    message: message,
    mode: 'chat'
  }
  
  try {
    ws.send(JSON.stringify(msg))
  } catch (error) {
    console.error('发送消息错误:', error)
    handleError()
  }
}

// 错误处理
const handleError = () => {
  ElMessage.error('发送消息失败，请重试')
  isThinking.value = false
  closeWebSocket()
}

// 关闭WebSocket连接
const closeWebSocket = () => {
  if (ws) {
    ws.close()
    ws = null
  }
}

// 关闭对话框
const handleClose = () => {
  if (isThinking.value) {
    ElMessage.warning('正在等待AI响应，请稍候...')
    return
  }
  closeWebSocket()
  messages.value = []
  userInput.value = ''
  dialogVisible.value = false
}

// 监听对话框显示状态
watch(() => props.modelValue, (newVal) => {
  if (newVal && !isConnected.value) {
    initWebSocket()
  }
})

// 组件挂载时初始化连接
onMounted(() => {
  if (props.modelValue) {
    initWebSocket()
  }
})

// 组件卸载时清理
onUnmounted(() => {
  if (ws) {
    ws.close()
    ws = null
  }
})
</script>

<style scoped>
.chat-container {
  display: flex;
  flex-direction: column;
  height: 60vh;
  gap: 20px;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 24px;
  background-color: #f5f7fa;
  border-radius: 8px;
}

.message {
  margin-bottom: 24px;
  display: flex;
  flex-direction: column;
}

.message-content {
  max-width: 85%;
  display: flex;
  flex-direction: column;
}

.user-message {
  align-items: flex-end;
}

.ai-message {
  align-items: flex-start;
}

.user-content {
  background-color: var(--el-color-primary);
  color: white;
  border-radius: 12px 12px 0 12px;
  padding: 12px 16px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.ai-content {
  background-color: white;
  border-radius: 12px 12px 12px 0;
  padding: 16px 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.chat-input {
  padding: 20px;
  background-color: white;
  border-top: 1px solid #ebeef5;
}

.input-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 12px;
  padding: 0 4px;
}

.hint {
  color: #909399;
  font-size: 12px;
}

.thinking-icon {
  animation: rotate 1s linear infinite;
  margin-right: 8px;
}

@keyframes rotate {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

:deep(.markdown-body) {
  font-size: 14px;
  line-height: 1.6;
  color: #2c3e50;
}

:deep(.markdown-body p) {
  margin: 8px 0;
}

:deep(.markdown-body pre) {
  background-color: #f6f8fa;
  padding: 16px;
  border-radius: 6px;
  margin: 12px 0;
  border: 1px solid #ebeef5;
}

:deep(.markdown-body code) {
  font-family: 'Courier New', Consolas, monospace;
  font-size: 13px;
  padding: 2px 6px;
  background-color: #f6f8fa;
  border-radius: 4px;
}

:deep(.markdown-body pre code) {
  padding: 0;
  background-color: transparent;
}

:deep(.markdown-body ul), :deep(.markdown-body ol) {
  padding-left: 24px;
  margin: 8px 0;
}

:deep(.markdown-body blockquote) {
  margin: 16px 0;
  padding: 0 16px;
  color: #666;
  border-left: 4px solid #dcdfe6;
}

/* 优化消息间距 */
.message + .message {
  margin-top: 20px;
}

/* 优化滚动条 */
.chat-messages::-webkit-scrollbar {
  width: 6px;
}

.chat-messages::-webkit-scrollbar-thumb {
  background-color: #dcdfe6;
  border-radius: 3px;
}

.chat-messages::-webkit-scrollbar-track {
  background-color: transparent;
}

.connection-status {
  padding: 10px 16px;
  margin: 0 24px 16px;
  background-color: #fff3e6;
  color: #e6a23c;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  transition: all 0.3s ease;
}

.connection-status.connected {
  background-color: #f0f9eb;
  color: #67c23a;
}

.status-icon {
  animation: pulse 2s infinite;
}

.connected .status-icon {
  animation: none;
}

@keyframes pulse {
  0% { opacity: 0.6; }
  50% { opacity: 1; }
  100% { opacity: 0.6; }
}

.reasoning-content {
  background-color: #f8f9fa;
  color: #606266;
  font-style: italic;
  padding: 16px 20px;
  border-radius: 12px 12px 12px 0;
  font-size: 14px;
  line-height: 1.6;
  white-space: pre-wrap;
  border-left: 3px solid #dcdfe6;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.thinking-content {
  background-color: #f4f4f5;
  color: #909399;
  font-style: italic;
  display: flex;
  align-items: center;
  padding: 12px 16px;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

:deep(.el-dialog__body) {
  padding: 24px 0 0;
}

:deep(.el-dialog__header) {
  padding: 20px 24px;
  margin-right: 0;
  border-bottom: 1px solid #ebeef5;
}
</style> 